package cn.virens.common.utils.number;

/**
 * Byte 工具类
 *
 * @author virens
 */
public class ByteUtil {
    public final static byte[] EMPTY_BYTES = new byte[0];

    /**
     * byte -&gt; hex
     *
     * @param b byte src
     * @return Hex's String
     */
    public static String toHex(byte b) {
        StringBuffer sw = new StringBuffer(2);

        sw.append(toHexDigit(b >> 4 & 0x0f));
        sw.append(toHexDigit(b & 0x0f));

        return sw.toString();
    }

    /**
     * byte[] -&gt; hex
     *
     * @param bytes byte array src
     * @return Hex's String
     */
    public static String toHex(byte... bytes) {
        int len = bytes.length;

        StringBuffer sw = new StringBuffer(len * 2);
        for (int i = 0; i < len; ++i) {
            sw.append(toHexDigit(bytes[i] >> 4 & 0x0f));
            sw.append(toHexDigit(bytes[i] & 0x0f));
        }

        return sw.toString();
    }

    /**
     * int -&gt; hex
     *
     * @param i int src
     * @return Hex's String
     */
    public static String toHex(int i) {
        return Integer.toHexString(i);
    }

    /**
     * int -&gt; hex (指定长度)
     *
     * @param i  int src
     * @param bs return bytes length
     * @return Hex's String
     */
    public static String toHex(int i, int bs) {
        final String hex = toHex(i);

        final int allLen = bs * 2;
        final int strLen = hex.length();

        if (strLen < allLen) {
            int padLen = allLen - strLen;

            StringBuilder sb = new StringBuilder();

            while ((padLen--) > 0) {
                sb.append('0');
            }

            sb.append(hex);

            return sb.toString();
        } else {
            return hex;
        }
    }

    /**
     * HEX 优化，默认长度为2的倍数
     *
     * @param hex String's Src
     * @return Hex's String
     */
    public static String toHex(String hex) {
        if (hex == null || hex.isEmpty()) {
            return "";
        } else if (hex.length() % 2 == 1) {
            return "0" + hex;
        } else {
            return hex;
        }
    }

    /**
     * hex -&gt; byte[]
     *
     * @param hex hex's string
     * @return bytes
     */
    public static byte[] toByte(String hex) {
        if (hex == null) return EMPTY_BYTES;
        if (hex.length() == 0) return EMPTY_BYTES;

        char[] cs = hex.toCharArray();
        byte[] bs = new byte[cs.length / 2 + cs.length % 2];

        for (int i = 0; i < bs.length; i++) {
            int i1 = 0x00; // 高字节
            int i2 = 0x00; // 低字节

            if (cs.length % 2 == 1) {
                // 如果传入的hex长度为单数，默认前面添0
                if (i == 0) {
                    i1 = toByteDigit('0') & 0x0f;
                    i2 = toByteDigit(cs[i]) & 0x0f;
                } else {
                    i1 = toByteDigit(cs[i * 2 - 1]) & 0x0f;
                    i2 = toByteDigit(cs[i * 2 - 0]) & 0x0f;
                }
            } else {
                i1 = toByteDigit(cs[i * 2 + 0]) & 0x0f;
                i2 = toByteDigit(cs[i * 2 + 1]) & 0x0f;
            }

            bs[i] = (byte) (i1 << 4 | i2);
        }

        return bs;
    }

    /**
     * hex -&gt; byte[] (指定byte数组长度)
     *
     * @param hex    hex's string
     * @param length return byte array length
     * @return bytes
     */
    public static byte[] toByte(String hex, int length) {
        if (hex == null) return EMPTY_BYTES;
        if (hex.length() == 0) return EMPTY_BYTES;

        final int allLen = length * 2;
        final int strLen = hex.length();

        if (strLen < allLen) {
            int padLen = allLen - strLen;

            StringBuilder sb = new StringBuilder();

            while ((padLen--) > 0) {
                sb.append('0');
            }

            sb.append(hex);

            return toByte(sb.toString());
        } else if (strLen > allLen) {
            return toByte(hex.substring((strLen - allLen), strLen));
        } else {
            return toByte(hex);
        }
    }

    /**
     * int -&gt; byte[]
     *
     * @param i int src
     * @return bytes
     */
    public static byte[] toByte(int i) {
        return new byte[]{(byte) i};
    }

    /**
     * int -&gt; byte[] (指定byte数组长度)
     *
     * @param i  int src
     * @param bs byte array length
     * @return bytes
     */
    public static byte[] toByte(int i, int bs) {
        byte[] result = new byte[bs];

        int offset = bs - 1;
        for (int j = 0; j < bs; j++) {
            result[offset - j] = (byte) ((i >> (j * 8)) & 0xff);
        }

        return result;
    }

    /**
     * long -&gt; byte[] (指定byte数组长度)
     *
     * @param i  long src
     * @param bs byte array length
     * @return bytes
     */
    public static byte[] toByte(long i, int bs) {
        byte[] result = new byte[bs];

        int offset = bs - 1;
        for (int j = 0; j < bs; j++) {
            result[offset - j] = (byte) ((i >> (j * 8)) & 0xff);
        }

        return result;
    }

    /**
     * byte -&gt; int
     *
     * @param b byte src
     * @return int
     */
    public static int toInt(byte b) {
        return b & 0xff;
    }

    /**
     * byte[] -&gt; int
     *
     * @param bs bytes
     * @return int
     */
    public static int toInt(byte... bs) {
        int result = 0x00000000;

        for (int i = 0; i < bs.length; i++) {
            result = (result << 8) | (bs[i] & 0xff);
        }

        return result;
    }

    /**
     * byte[] -&gt; float
     *
     * @param bs bytes
     * @return float
     */
    public static float toFloat(byte... bs) {
        int result = 0x00000000;

        for (int i = 0; i < bs.length; i++) {
            result = (result << 8) | (bs[i] & 0xff);
        }

        return Float.intBitsToFloat(result);
    }

    /**
     * byte 数组转 Ascii
     *
     * @param bs bytes
     * @return ascii string
     */
    public static String toAscii(byte... bs) {
        char[] cs = new char[bs.length];

        for (int i = 0; i < bs.length; i++) {
            cs[i] = (char) bs[i];
        }

        return new String(cs);
    }

    /**
     * hex -&gt; int
     *
     * @param hex hex's string
     * @return int
     */
    public static int toInt(String hex) {
        if (hex == null || hex.isEmpty()) return 0;

        char[] cs = hex.toCharArray();

        int res = 0;
        int len = cs.length;
        for (int i = 0; i < len; i++) {
            res = res | ((toByteDigit(cs[i]) & 0x0f) << ((len - i - 1) * 4));
        }

        return res;
    }

    /**
     * CRC生成
     *
     * @param regInit    初始值
     * @param polynomial 多项式
     * @param bytes      待校验数组
     * @return CRC值
     */
    public static int toCRC0(int regInit, int polynomial, byte[] bytes) {
        return toCRC(regInit, Integer.reverse(polynomial), bytes);
    }

    /**
     * CRC生成
     *
     * @param regInit    初始值
     * @param polynomial 多项式（需要反转）
     * @param bytes      待校验数组
     * @return CRC值
     */
    public static int toCRC(int regInit, int polynomial, byte[] bytes) {
        for (int i = 0; i < bytes.length; i++) {
            regInit = (regInit & 0xff00) | (regInit ^ bytes[i] & 0x00ff);

            for (int j = 0; j < 8; j++) {
                if ((regInit & 0x0001) == 0x0001) {
                    regInit = regInit >> 1 & 0x7fff;
                    regInit = regInit ^ polynomial;
                } else {
                    regInit = regInit >> 1 & 0x7fff;
                }
            }
        }

        return regInit & 0xffff;
    }

    /**
     * 转换二进制字符串
     *
     * @param bs bytes src
     * @return binary's string
     */
    public static String toBinary(byte... bs) {
        StringBuilder builder = new StringBuilder();

        for (byte b : bs) {
            builder.append(b >> 7 & 0x01);
            builder.append(b >> 6 & 0x01);
            builder.append(b >> 5 & 0x01);
            builder.append(b >> 4 & 0x01);
            builder.append(b >> 3 & 0x01);
            builder.append(b >> 2 & 0x01);
            builder.append(b >> 1 & 0x01);
            builder.append(b & 0x01);
        }

        return builder.toString();
    }

    /**
     * 获取HEX 的字节长度
     *
     * @param hex hex's string
     * @return hes's length
     */
    public static int length(String hex) {
        if (hex == null) return 0;
        int len = hex.length();

        if (len % 2 == 0) {
            return len / 2;
        } else {
            return len / 2 + 1;
        }
    }

    private static char toHexDigit(int i) {
        if (i <= 9) {
            return (char) (i + 0x30);
        } else {
            return (char) (i + 0x57);
        }
    }

    private static int toByteDigit(char c1) {
        if (c1 >= '0' && c1 <= '9') {
            return (c1 - 0x30);
        } else if (c1 >= 'A' && c1 <= 'Z') {
            return (c1 - 0x27);
        } else if (c1 >= 'a' && c1 <= 'z') {
            return (c1 - 0x57);
        } else {
            return 0;
        }
    }
}
